import Cesium from '../Ces/Cesium'
import WeVolumeShaders from './WeVolumeShaders'
import WeDisplayParameter from './WeDisplayParameter'
import WeDisplayShaders from './WeDisplayShaders'

const { fixMaterialsSourface } = WeDisplayShaders
const {
  WeVolumeBoxVS, WeVolumeBoxFS,
} = WeVolumeShaders

class WeVolumeBox {
  private _primitive
  private debug
  private _primitiveDebug

  constructor(options) {
    const {
      width, height, extrudedHeight, onwer, display, modelMatrix, fragmentMain,
      extraUniform
    } = options

    this.debug = options.debug??false

    const halfWidth = width * 0.5
    const halfHeight = height * 0.5

    const geometry = Cesium.BoxGeometry.createGeometry(
      new Cesium.BoxGeometry({
        maximum: new Cesium.Cartesian3(halfWidth, halfHeight, extrudedHeight),
        minimum: new Cesium.Cartesian3(-halfWidth, -halfHeight, 0.0),
        vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
      }),
    )

    const texgen = new Cesium.Matrix4(
      1.0 / width, 0.0, 0.0, 0.0,
      0.0, 1.0 / height, 0.0, 0.0,
      0.0, 0.0, 1.0 / extrudedHeight, 0.0,
      0.5, 0.5, 0.0, 1.0,
    )

    const translucent = true

    const rectangle = options.rectangle

    const uniforms = {
      u_texgen: texgen,
      u_localExtent: new Cesium.Cartesian4(rectangle.west, rectangle.south, rectangle.east, rectangle.north),
    }

    if (extraUniform) {
      extraUniform.setupUniform(uniforms)
    }
    display.setupUniform(uniforms)

    WeDisplayParameter.setupUniform(uniforms)

    const baseFragmentSource = display.getFragmentShaderSource(true, true, false)

    let fragmentShaderSource = `
    ${WeDisplayShaders.WePhong}
    ${baseFragmentSource}
    ${WeDisplayParameter.getSource(false)}
    ${extraUniform ? extraUniform.getSource(false) : ''}
    ${fragmentMain || WeVolumeBoxFS}
      `

    fragmentShaderSource = fixMaterialsSourface(fragmentShaderSource, uniforms)
    const appearance = new Cesium.MaterialAppearance({
      renderState: {
        depthTest: { enabled: true },
        depthMask: true,
        blending: Cesium.BlendingState.ALPHA_BLEND,
        cull: {
          enabled: true,
          face: Cesium.CullFace.FRONT,
        },
      },
      translucent,
      vertexShaderSource: WeVolumeBoxVS,
      fragmentShaderSource,
      material: new Cesium.Material({
        translucent,
        fabric: {
          uniforms,
        },
      }),
    })

    display.fixMaterials(appearance.material)

    const primitive = new Cesium.Primitive({
      geometryInstances: new Cesium.GeometryInstance({
        geometry,
      }),
      asynchronous: false,
      appearance,
    })

    primitive.id = onwer
    primitive.modelMatrix = modelMatrix
    this._primitive = primitive

    if (this.debug) {
      const geometry = new Cesium.RectangleOutlineGeometry({
        ellipsoid: Cesium.Ellipsoid.WGS84,
        rectangle,
        extrudedHeight: extrudedHeight * WeDisplayParameter.scaleZ,
      })
      const g2 = Cesium.RectangleOutlineGeometry.createGeometry(geometry)

      const values = g2.attributes.position.values
      const minBound = new Cesium.Cartesian3(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY)
      const maxBound = new Cesium.Cartesian3(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY)
      for (let i = 0; i < values.length; i += 3) {
        const x = values[i]
        const y = values[i + 1]
        const z = values[i + 2]
        minBound.x = Math.min(minBound.x, x)
        minBound.y = Math.min(minBound.y, y)
        minBound.z = Math.min(minBound.z, z)
        maxBound.x = Math.max(maxBound.x, x)
        maxBound.y = Math.max(maxBound.y, y)
        maxBound.z = Math.max(maxBound.z, z)
      }

      const cartographicMin = Cesium.Cartographic.fromCartesian(minBound, undefined, new Cesium.Cartographic())
      const cartographicMax = Cesium.Cartographic.fromCartesian(maxBound, undefined, new Cesium.Cartographic())
      const height = cartographicMax.height - cartographicMin.height

      const center = Cesium.Cartesian3.add(minBound, maxBound, new Cesium.Cartesian3())
      Cesium.Cartesian3.multiplyByScalar(center, 0.5, center)

      Cesium.Cartesian3.subtract(minBound, center, minBound)
      Cesium.Cartesian3.subtract(maxBound, center, maxBound)

      const halfWidth1 = maxBound.x
      const halfHeight1 = maxBound.y
      const geometry2 = Cesium.BoxOutlineGeometry.createGeometry(
        new Cesium.BoxOutlineGeometry({
          minimum: minBound,
          maximum: maxBound,
          // maximum1: new Cesium.Cartesian3(halfWidth, halfHeight, height * 0.5),
          // minimum1: new Cesium.Cartesian3(-halfWidth, -halfHeight, -height * 0.5),
          vertexFormat: Cesium.VertexFormat.POSITION,
        }),
      )

      const solidWhite = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.WHITE)
      const solidRed = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.RED)
      const solidBlue = Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE)
      this._primitiveDebug = new Cesium.PrimitiveCollection()

      this._primitiveDebug.add(new Cesium.Primitive({
        geometryInstances: new Cesium.GeometryInstance({
          geometry,
          attributes: {
            color: solidBlue
          }
        }),
        asynchronous: false,
        appearance: new Cesium.PerInstanceColorAppearance({
          flat: true,
          translucent: false,
        })
      }))

      const westSouth = Cesium.Cartesian3.fromRadians(rectangle.west, rectangle.south)
      const easrNorth = Cesium.Cartesian3.fromRadians(rectangle.east, rectangle.north)
      Cesium.Cartesian3.add(westSouth, easrNorth, center)
      Cesium.Cartesian3.multiplyByScalar(center, 0.5, center)
      const centerCartorgraphic = Cesium.Cartographic.fromCartesian(center)

      const modelMatrix1 = new Cesium.Matrix4()
      Cesium.Transforms.eastNorthUpToFixedFrame(center, undefined, modelMatrix1)
      Cesium.Matrix4.multiplyByScale(modelMatrix1, { x: 1.0, y: 1.0, z: WeDisplayParameter.scaleZ }, modelMatrix1)

      const pointCollection = this._primitiveDebug.add(new Cesium.PointPrimitiveCollection())
      pointCollection.add({
        position: center
      })
      pointCollection.add({
        position: westSouth
      })
      pointCollection.add({
        position: easrNorth
      })
      pointCollection.add({
        position: Cesium.Cartesian3.fromRadians(
          rectangle.west + rectangle.width * 0.5,
          rectangle.south + rectangle.height * 0.5,
        )
      })

      // this._primitiveDebug.add(new Cesium.Primitive({
      //   geometryInstances: new Cesium.GeometryInstance({
      //     geometry: geometry2,
      //     attributes: {
      //       color: solidWhite
      //     },
      //     modelMatrix: modelMatrix1
      //   }),
      //   asynchronous: false,
      //   appearance: new Cesium.PerInstanceColorAppearance({
      //     flat: true,
      //     translucent: false,
      //   })
      // }))

      this._primitiveDebug.add(new Cesium.Primitive({
        geometryInstances: new Cesium.GeometryInstance({
          geometry: Cesium.BoxOutlineGeometry.createGeometry(
            new Cesium.BoxOutlineGeometry({
              maximum: new Cesium.Cartesian3(halfWidth, halfHeight, extrudedHeight),
              minimum: new Cesium.Cartesian3(-halfWidth, -halfHeight, 0.0),
              vertexFormat: Cesium.VertexFormat.POSITION,
            }),
          ),
          attributes: {
            color: solidRed
          },
          modelMatrix
        }),
        asynchronous: false,
        appearance: new Cesium.PerInstanceColorAppearance({
          flat: true,
          translucent: false,
        })
      }))


      // this._primitiveDebug.add(new Cesium.Primitive({
      //   geometryInstances: new Cesium.GeometryInstance({
      //     geometry: Cesium.BoxOutlineGeometry.createGeometry(
      //       new Cesium.BoxOutlineGeometry({
      //         maximum: new Cesium.Cartesian3(halfWidth, halfHeight, extrudedHeight),
      //         minimum: new Cesium.Cartesian3(-halfWidth, -halfHeight, 0.0),
      //         vertexFormat: Cesium.VertexFormat.POSITION,
      //       }),
      //     ),
      //     attributes: {
      //       color: solidWhite
      //     },
      //     modelMatrix: modelMatrix1
      //   }),
      //   asynchronous: false,
      //   appearance: new Cesium.PerInstanceColorAppearance({
      //     flat: true,
      //     translucent: false,
      //   })
      // }))
    }
  }


  isDestroyed() {
    return false
  }

  destroy() {
    this._primitive = this._primitive && this._primitive.destroy()
    this._primitiveDebug = this._primitiveDebug && this._primitiveDebug.destroy()

    return Cesium.destroyObject(this)
  }

  update(frameState) {
    this._primitive.update(frameState)
    if (this._primitiveDebug) {
      this._primitiveDebug.update(frameState)
    }
  }

}



export default WeVolumeBox
